package cn.uikit.demo.recyclerview.layoutManager

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.Recycler
import androidx.recyclerview.widget.RecyclerView.State
import kotlin.math.abs

class StackLayoutManager : RecyclerView.LayoutManager() {

    //一次完整的聚焦滑动所需要的距离
    private var onceCompleteScrollLength = -1

    //第一个Item横向完全滚动出屏幕需要移动的距离
    private var firstChildCompleteScrollLength = -1

    private var firstItemOffsetX = -1

    //屏幕中第一个可见的view的pos
    private var mFirstVisiblePos = 0

    private var mLastVisiblePos = 0

    //水平方向的累积偏移位移
    private var mHorizontalOffset = 0

    //item 间的位移
    private var itemViewGap = 0

    //
    private var childWidth = 0

    //是否自动选中
    private var isAutoSelect = true

    //第一个item的便宜
    private var firstChildOffsetX = 0

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            RecyclerView.LayoutParams.WRAP_CONTENT,
            RecyclerView.LayoutParams.WRAP_CONTENT
        )
    }


    override fun canScrollHorizontally() = true


    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: State) {
        super.onLayoutChildren(recycler, state)
        if (state.itemCount == 0) {
            // 没有数据时清空所有视图
            removeAndRecycleAllViews(recycler)
            return
        }
        fill(recycler, state, 0)
    }

    private fun fill(recycler: Recycler, state: State, dx: Int): Int {
        val resultDelta = fillHorizontalLeft(recycler, state, dx)
        recycleChildren(recycler)
        return resultDelta
    }

    private fun fillHorizontalLeft(recycler: Recycler, state: State, offsetX: Int): Int {
        var dx = offsetX
        //----------------1、边界检测-----------------
        if (dx < 0) {
            // 已到达左边界
            if (mHorizontalOffset < 0) {
                dx = 0
                mHorizontalOffset = 0
            }
        }

        if (dx > 0) {
            if (mHorizontalOffset >= maxOffset()) {
                mHorizontalOffset = maxOffset()
                dx = 0
            }
        }

        // 分离全部的view，加入到临时缓存
        detachAndScrapAttachedViews(recycler)

        var startX = 0

        var tempView: View? = null
        var tempPosition = -1

        //测量出第一个item的width
        if (onceCompleteScrollLength == -1) {
            // 因为mFirstVisiblePos在下面可能被改变，所以用tempPosition暂存一下
            tempPosition = mFirstVisiblePos
        }

        if (firstItemOffsetX == -1) {
            val firstView = recycler.getViewForPosition(0)
            measureChildWithMargins(firstView, 0, 0)
            childWidth = getDecoratedWidthWithMargin(firstView)
            firstItemOffsetX = (width - childWidth) / 2
        }

        //当前滚动已经将第一个item滚动出屏幕
        if (mHorizontalOffset >= firstChildOffsetX) {
            startX = (width - childWidth) / 2 - mHorizontalOffset
        } else { //第一个item还在屏幕中
            mFirstVisiblePos = 0
            startX = firstChildOffsetX - mHorizontalOffset
        }

        mLastVisiblePos = itemCount - 1
        for (i in mFirstVisiblePos..mLastVisiblePos) {
            val childView = if (i == tempPosition && tempView != null) {
                // 如果初始化数据时已经取了一个临时view
                tempView
            } else {
                recycler.getViewForPosition(i)
            }
            addView(childView)
            measureChildWithMargins(childView, 0, 0)
            val l = startX
            val t = paddingTop
            val r = l + getDecoratedWidthWithMargin(childView)
            val b = t + getDecoratedHeightMargin(childView)
            layoutDecoratedWithMargins(childView, l, t, r, b)
            startX += (childView.width + itemViewGap)
            if (startX > width - paddingRight) {
                mLastVisiblePos = i
                break
            }
        }
        return dx
    }


    override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler, state: State): Int {
        if (childCount == 0 || state.itemCount == 0) return 0
        val realDx = dx / 1.0f
        if (abs(realDx.toDouble()) < 0.00000001f) {
            return 0
        }

        mHorizontalOffset += dx
        return fill(recycler, state, dx)
    }


    private fun recycleInvisibleViews(
        recycler: RecyclerView.Recycler,
        parentLeft: Int,
        parentRight: Int
    ) {
        for (i in childCount - 1 downTo 0) {
            val child = getChildAt(i) ?: continue

            val childRight = getDecoratedRight(child)
            val childLeft = getDecoratedLeft(child)
            // 检查视图是否完全离开可见区域
            if (childRight <= parentLeft || childLeft >= parentRight) {
                removeAndRecycleView(child, recycler)
            }
        }
    }


    private fun recycleChildren(recycler: Recycler) {
        val scrapList = recycler.scrapList
        for (i in scrapList.indices) {
            val holder = scrapList[i]
            removeAndRecycleView(holder.itemView, recycler)
        }
    }

    /**
     *获取childView在水平方向上做占据的空间,将margin考虑进去
     */
    private fun getDecoratedWidthWithMargin(view: View): Int {
        val lp = view.layoutParams as RecyclerView.LayoutParams
        return getDecoratedMeasuredWidth(view) + lp.leftMargin + lp.rightMargin
    }

    private fun getDecoratedHeightMargin(view: View): Int {
        val lp = view.layoutParams as RecyclerView.LayoutParams
        return getDecoratedMeasuredHeight(view) + lp.topMargin + lp.bottomMargin
    }


    private fun maxOffset(): Int {
        if (childWidth == 0 || itemCount == 0) {
            return 0
        }
        return (childWidth + itemViewGap) * (itemCount - 1)
    }

    private fun getMinOffset(): Int {
        if (childWidth == 0) return 0
        return (width - childWidth) / 2
    }

}